This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

plot(rnorm(100))

plot(cars)

# Data Visualization
# ggplot2 "grammar of graphics"
#libraries need to be reloaded for every new session
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages -------------------------------
filter(): dplyr, stats
lag():    dplyr, stats

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

# 3.2 
# do cars with large engines use more fuel than cars with small engines?
# what does the relationship between engine size and fuel efficiency look like?
# use mpg: a data frame containing observations collected by USEPA on cars
mpg

image of the mpg data frame

# plot of the mpg data using ggplot2
# displ, a car's engine size, is on the x-axis
# hwy, a car's highway efficiency, on the y-axis
#geom_point() adds a 'layer' to this graph and makes it a scattor plot
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy))

–plot of the data from ‘mpg’ , plotting a car’s engine sie on the x-axis, against its highway efficiency on the y-axis –looks like cars with largeer engines use more feul (duh)

ggplot(data = mpg) +
  geom_point(mapping = aes(x = hwy, y = cyl))

# 3.3 Aesthetic Mappings 
# adding a 3rd var to a 2D scatter by adding a visual proerty to an object in your plot
# reproduction of the above plot with class added as a color
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, color = class))

#class is an unordered var, so it may not be optimal to map it using size
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, size = class))

# alpha is transparency
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, alpha = class))

# shape has six shapes used
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, shape = class))

r rules

# the aesthetic properties may be manually set
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), color = "pink")

# the aesthetic properties may be manually set
#
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, size = cty))

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = cty))

These plots set a continuous variable (city mileage) to different aedthetic markers

# 3.5 Facets
# another method for multi variable data plotting
# var to facet wrap should be discrete
#example of 1 variable faceting
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_wrap(~class, nrow = 2)

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(.~class)

A plot of highway mileage against display, faceted by class of vehicle, one variable

# example of 2-var faceting
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(drv~class)

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(drv~cyl)

Plot of data faceted on two variables

# 3.6 Geometric Objects
# a 'geom' is the geometrical object that a plot uses to represent data
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))

ggplot(data = mpg) + 
  geom_smooth(mapping = aes(x = displ, y = hwy))

# these on the same plot
#note: pass the mappings to the ggplot function to avoid duplication errors
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point() + 
  geom_smooth()

different geometric representations of the same data

#different aesthetics can be displayed in different layers
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point(mapping = aes(color = class)) + 
  geom_smooth()

same plot as fig 14.c , with the scatter plot colored by class

# local data arguments will override globals 
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point(mapping = aes(color = class)) + 
  geom_smooth(data = filter(mpg, class == "subcompact"), se = FALSE)

Same plot as fig 15 with line filtered to include only class subcompact

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + 
  geom_point() + 
  geom_smooth(se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point() + 
  geom_smooth(mapping = aes(group = drv))

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point(mapping = aes(color = drv)) + 
  geom_smooth(se = FALSE)

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
  geom_point(mapping = aes(color = drv)) + 
  geom_smooth(mapping = aes(linetype = drv), se = FALSE)

# Statistical Transforms
#bar charts, histograms, frequency polygons bin and count data
#smoothers fit a model to your data, plot predictions come from this model 
# box plots compute a summary of the distribution of the data
#stat_plot can be used instead of geom_bar here
ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut))

chart of diamond count by cut quality

# use geom_bar to override the default stat
demo <- tribble(
  ~cut,         ~freq,
  "Fair",       1610,
  "Good",       4906,
  "Very Good",  12082,
  "Premium",    13791,
  "Ideal",      21551
)
ggplot(data = demo) +
  geom_bar(mapping = aes(x = cut, y = freq), stat = "identity")

ggplot(data = diamonds) + 
  stat_summary(
    mapping = aes(x = cut, y = depth),
    fun.ymin = min,
    fun.ymax = max,
    fun.y = median
  )

fig a :plotted against frequency, not simply count fig b: statistics summary of cut against depth

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = clarity))

ggplot(data = diamonds, mapping = aes(x = cut, fill = clarity)) + 
  geom_bar(alpha = 1/5, position = "identity")

ggplot(data = diamonds, mapping = aes(x = cut, colour = clarity)) + 
  geom_bar(fill = NA, position = "identity")

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = clarity), position = "fill")

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = clarity), position = "dodge")

Colored Graphs,introduces a new var, organized by position adjustment

# jitter to view all data points with a small amount of noise, as view all of them
#some will be obscured
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), position = "jitter")

Jittered vs. non-jittered

# 3.9 Coordinate systems
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) + 
  geom_boxplot()

ggplot(data = mpg, mapping = aes(x = class, y = hwy)) + 
  geom_boxplot() +
  coord_flip()

flipping coordinate systems is useful for displaying horizantal boxplots

install.packages("maps")
Installing package into ‘/Users/sarahbarili/Library/R/3.3/library’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/macosx/mavericks/contrib/3.3/maps_3.1.1.tgz'
Content type 'application/x-gzip' length 3601273 bytes (3.4 MB)
==================================================
downloaded 3.4 MB

The downloaded binary packages are in
    /var/folders/ph/sb4qh05n1c33wyrwt1mbzz8c0000gp/T//Rtmpz04d4l/downloaded_packages
library(maps)

Attaching package: ‘maps’

The following object is masked from ‘package:purrr’:

    map
nz<- map_data("nz")
ggplot(nz, aes(long,lat, group = group)) +
  geom_polygon(fill = "pink", colour = "black")

#coord_quickmap sets the correct ratio for geospatial data
ggplot(nz, aes(long, lat, group = group)) +
  geom_polygon(fill = "pink", colour = "black") +
  coord_quickmap()

bar <- ggplot(data = diamonds) + 
  geom_bar(
    mapping = aes(x = cut, fill = cut), 
    show.legend = FALSE,
    width = 1
  ) + 
  theme(aspect.ratio = 1) +
  labs(x = NULL, y = NULL)
bar + coord_flip()

bar + coord_polar()

# Data Transformation
library(nycflights13)
library(tidyverse)
flights
# 5.2 filter
# select all flights on Jan 1st
jan1 <-filter(flights, month == 1, day == 1)
jan1
nov_dec <- filter(flights, month %in% c(11, 12))
nov_dec2 <- filter(flights, month == 11 | month == 12)
# 5.3 Arrange
arrange(flights, year, month, day)
arrange(flights, desc(arr_delay))
# 5.6 Grouped Summaries
by_day <- group_by(flights, year, month, day)
summarise(by_day, delay = mean(dep_delay, na.rm = TRUE))
# explore the relationship betweem the distance and the ang. delay for each location
#group flights by destination
#summarize to compute distance, average delay, # of flights
#filter outliers and honolulu
#na.rm = TRUE removes missing values
by_dest <- group_by(flights, dest)
delay <- summarise(by_dest,
    count = n(),
    dist = mean(distance, na.rm = TRUE),
    delay = mean(arr_delay, na.rm = TRUE)
)
delay <- filter(delay,count >20, dest != "HNL")
ggplot(data = delay, mapping = aes(x = dist, y = delay)) +
  geom_point(aes(size = count), alpha = 1/3) +
  geom_smooth(se = FALSE)

#using pipes to make variable naming and analysis easier
delays <- flights %>% 
  group_by(dest) %>% 
  summarise(
    count = n(),
    dist = mean(distance, na.rm = TRUE),
    delay = mean(arr_delay, na.rm = TRUE)
  ) %>% 
  filter(count > 20, dest != "HNL")
batting <- as_tibble(Lahman::Batting)
batters <- batting %>% 
  group_by(playerID) %>% 
  summarise(
    ba = sum(H, na.rm = TRUE) / sum(AB, na.rm = TRUE),
    ab = sum(AB, na.rm = TRUE)
  )
batters %>% 
  filter(ab > 100) %>% 
  ggplot(mapping = aes(x = ab, y = ba)) +
    geom_point() + 
    geom_smooth(se = FALSE)

#> `geom_smooth()` using method = 'gam'
# 7 Exploratory Data Analysis
#Generate Questions about your data
#search for answers using visualization and transformation, and modeling
#use what you learn to refine your questions and generate new questions
# 7.3 Variation
# tendency of the values of a variable to change from measureent to measurement
# visualizing distributions: categporical or continuous 
# categorical -- use a bar chart
ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut))

diamonds %>%
  count(cut)

the hieght of the bars shows how many observations of the data occured at each x value

# use a histgram for continuous data
# binwidth organizes each value with set boundaries
ggplot(data = diamonds) +
  geom_histogram(mapping = aes(x = carat), binwidth = 0.5)

diamonds %>% 
  count(cut_width(carat, 0.5))
#Different binwidths could reveal different realtionships in the data
smaller <- diamonds %>% 
  filter(carat < 3)
  
ggplot(data = smaller, mapping = aes(x = carat)) +
  geom_histogram(binwidth = 0.1)

ggplot(data = smaller, mapping = aes(x = carat, colour = cut)) +
  geom_freqpoly(binwidth = 0.1)

ggplot(data = faithful, mapping = aes(x = eruptions)) + 
  geom_histogram(binwidth = 0.1)

# 7.5 Covariation
# tencdency for two values to be related
# how does the price of a diamond vary with its quality?
ggplot(data = diamonds, mapping = aes(x = cut, y = price)) +
  geom_boxplot()

ggplot(data = diamonds, mapping = aes(x = price, y = ..density..)) + 
  geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)

ggplot(diamonds) + 
  geom_bar(mapping = aes(x = cut))

# how does highway mileage vary across classes of vehicles?
ggplot(data = mpg) +
  geom_boxplot(mapping = aes(x = reorder(class, hwy, FUN = median), y = hwy))

# Two categorical variables
ggplot(data = diamonds) +
  geom_count(mapping = aes(x = cut, y = color))

diamonds %>% 
  count(color, cut) %>%  
  ggplot(mapping = aes(x = color, y = cut)) +
    geom_tile(mapping = aes(fill = n))

# two continuous variables
ggplot(data = diamonds) +
  geom_point(mapping = aes(x = carat, y = price))

#binning for two continuous variables is helpful to visualize large data
ggplot(data = smaller) +
  geom_bin2d(mapping = aes(x = carat, y = price))

install.packages("hexbin")
Installing package into ‘/Users/sarahbarili/Library/R/3.3/library’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/macosx/mavericks/contrib/3.3/hexbin_1.27.1.tgz'
Content type 'application/x-gzip' length 773778 bytes (755 KB)
==================================================
downloaded 755 KB

The downloaded binary packages are in
    /var/folders/ph/sb4qh05n1c33wyrwt1mbzz8c0000gp/T//Rtmpz04d4l/downloaded_packages
ggplot(data = smaller) +
  geom_hex(mapping = aes(x = carat, y = price))

#another option is to bin one continuous variable so it behaves like a categorical variable
ggplot(data = smaller, mapping = aes(x = carat, y = price)) + 
  geom_boxplot(mapping = aes(group = cut_width(carat, 0.1)))

# 7 Patterns and models
# build a model that predicts price from carat
#computes residuals
library(modelr)
mod <- lm(log(price) ~ log(carat), data = diamonds)
diamonds2 <- diamonds %>% 
  add_residuals(mod) %>% 
  mutate(resid = exp(resid))
ggplot(data = diamonds2) + 
  geom_point(mapping = aes(x = carat, y = resid))

relative to size, better quality diamonds are more expensive

ggplot(data = diamonds2) + 
  geom_boxplot(mapping = aes(x = cut, y = resid))

# same code
ggplot(data = faithful, mapping = aes(x = eruptions)) + 
  geom_freqpoly(binwidth = 0.25)

ggplot(faithful, aes(eruptions)) + 
  geom_freqpoly(binwidth = 0.25)

#Data Wrangling
#getting your data into R 
#import, tidy, transform
# 10 Tibbles
# tibbles are data frames 
library(tidyverse)
#coerce a regualr data frame to a tibble
as_tibble(iris)
#create a 5X3 tibble
tibble(
  x = 1:5, 
  y = 1, 
  z = x ^ 2 + y
)
tibble(
  a = lubridate::now() + runif(1e3) * 86400,
  b = lubridate::today() + runif(1e3) * 30,
  c = 1:1e3,
  d = runif(1e3),
  e = sample(letters, 1e3, replace = TRUE)
)
#tibbles will automatically print the first 10 rows of a tibble
#this can be customized
nycflights13::flights %>% 
  print(n = 10, width = Inf)
df <- tibble(
  x = runif(5),
  y = rnorm(5)
)
# Subsetting
# [[ ]] extracts by name or position
df[[1]]
[1] 0.4117549 0.8229977 0.2308909 0.5321475 0.3877842
df[["x"]]
[1] 0.4117549 0.8229977 0.2308909 0.5321475 0.3877842
# $ extracts by name wih less typing
df$x
[1] 0.4117549 0.8229977 0.2308909 0.5321475 0.3877842
#use in a pipe
df %>% .$x
[1] 0.4117549 0.8229977 0.2308909 0.5321475 0.3877842
df %>% .[["x"]]
[1] 0.4117549 0.8229977 0.2308909 0.5321475 0.3877842
# 23  Model Basics
library(tidyverse)
library(modelr)
options(na.action = na.warn)
# Define a family of models that express a precise, but generic pattern (i.e. a line, quadratic, etc)
# generate a fitted model by making the generic model more specific
ggplot(sim1, aes(x, y)) + 
  geom_point()

Simulated Plot with a strong pattern

#randomly generate a few models and overlay them on the data
models <- tibble(
  a1 = runif(250, -20, 40),
  a2 = runif(250, -5, 5)
)
ggplot(sim1, aes(x, y)) + 
  geom_abline(aes(intercept = a1, slope = a2), data = models, alpha = 1/4) +
  geom_point()

Our data with a bunch of shitty models

# quantify the distance between the data and a model
# generate model with the smallest distance from the data 
# Step 1: turn model family into an R function
model1 <- function(a, data) {
  a[1] + data$x * a[2]
}
model1(c(7, 1.5), sim1)
 [1]  8.5  8.5  8.5 10.0 10.0 10.0 11.5 11.5 11.5 13.0 13.0
[12] 13.0 14.5 14.5 14.5 16.0 16.0 16.0 17.5 17.5 17.5 19.0
[23] 19.0 19.0 20.5 20.5 20.5 22.0 22.0 22.0
measure_distance <- function(mod, data) {
  diff <- data$y - model1(mod, data)
  sqrt(mean(diff ^ 2))
}
# root-mean-squared deviation
measure_distance(c(7, 1.5), sim1)
[1] 2.665212
#use purrr function to compute the distance for all bove defined models
sim1_dist <- function(a1, a2) {
  measure_distance(c(a1, a2), sim1)
}
models <- models %>% 
  mutate(dist = purrr::map2_dbl(a1, a2, sim1_dist))
models
# overlay the 10 best models onto the the data
ggplot(sim1, aes(x, y)) + 
  geom_point(size = 2, colour = "grey30") + 
  geom_abline(
    aes(intercept = a1, slope = a2, colour = -dist), 
    data = filter(models, rank(dist) <= 10)
  )

ggplot(sim1, aes(x, y)) + 
  geom_point(size = 2, colour = "grey30") + 
  geom_abline(
    aes(intercept = a1, slope = a2, colour = -dist), 
    data = filter(models, rank(dist) <= 1)
  )

ggplot(models, aes(a1, a2)) +
  geom_point(data = filter(models, rank(dist) <= 10), size = 4, colour = "red") +
  geom_point(aes(colour = -dist))

#grid search for best model
grid <- expand.grid(
  a1 = seq(-5, 20, length = 25),
  a2 = seq(1, 3, length = 25)
  ) %>% 
  mutate(dist = purrr::map2_dbl(a1, a2, sim1_dist))
grid %>% 
  ggplot(aes(a1, a2)) +
  geom_point(data = filter(grid, rank(dist) <= 10), size = 4, colour = "red") +
  geom_point(aes(colour = -dist)) 

ggplot(sim1, aes(x, y)) + 
  geom_point(size = 2, colour = "grey30") + 
  geom_abline(
    aes(intercept = a1, slope = a2, colour = -dist), 
    data = filter(grid, rank(dist) <= 10)
  )

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCmBgYHtyfQpwbG90KHJub3JtKDEwMCkpCmBgYAoKYGBge3J9CnBsb3QoY2FycykKYGBgCmBgYHtyfQojIERhdGEgVmlzdWFsaXphdGlvbgojIGdncGxvdDIgImdyYW1tYXIgb2YgZ3JhcGhpY3MiCiNsaWJyYXJpZXMgbmVlZCB0byBiZSByZWxvYWRlZCBmb3IgZXZlcnkgbmV3IHNlc3Npb24KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLgpgYGB7cn0KIyAzLjIgCiMgZG8gY2FycyB3aXRoIGxhcmdlIGVuZ2luZXMgdXNlIG1vcmUgZnVlbCB0aGFuIGNhcnMgd2l0aCBzbWFsbCBlbmdpbmVzPwojIHdoYXQgZG9lcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZW5naW5lIHNpemUgYW5kIGZ1ZWwgZWZmaWNpZW5jeSBsb29rIGxpa2U/CiMgdXNlIG1wZzogYSBkYXRhIGZyYW1lIGNvbnRhaW5pbmcgb2JzZXJ2YXRpb25zIGNvbGxlY3RlZCBieSBVU0VQQSBvbiBjYXJzCm1wZwpgYGAKaW1hZ2Ugb2YgdGhlIG1wZyBkYXRhIGZyYW1lCmBgYHtyfQojIHBsb3Qgb2YgdGhlIG1wZyBkYXRhIHVzaW5nIGdncGxvdDIKIyBkaXNwbCwgYSBjYXIncyBlbmdpbmUgc2l6ZSwgaXMgb24gdGhlIHgtYXhpcwojIGh3eSwgYSBjYXIncyBoaWdod2F5IGVmZmljaWVuY3ksIG9uIHRoZSB5LWF4aXMKI2dlb21fcG9pbnQoKSBhZGRzIGEgJ2xheWVyJyB0byB0aGlzIGdyYXBoIGFuZCBtYWtlcyBpdCBhIHNjYXR0b3IgcGxvdApnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQpgYGAKLS1wbG90IG9mIHRoZSBkYXRhIGZyb20gJ21wZycgLCBwbG90dGluZyBhIGNhcidzIGVuZ2luZSBzaWUgb24gdGhlIHgtYXhpcywgYWdhaW5zdCBpdHMgaGlnaHdheSBlZmZpY2llbmN5IG9uIHRoZSB5LWF4aXMKLS1sb29rcyBsaWtlIGNhcnMgd2l0aCBsYXJnZWVyIGVuZ2luZXMgdXNlIG1vcmUgZmV1bCAoZHVoKQpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGh3eSwgeSA9IGN5bCkpCmBgYApgYGB7cn0KIyAzLjMgQWVzdGhldGljIE1hcHBpbmdzIAojIGFkZGluZyBhIDNyZCB2YXIgdG8gYSAyRCBzY2F0dGVyIGJ5IGFkZGluZyBhIHZpc3VhbCBwcm9lcnR5IHRvIGFuIG9iamVjdCBpbiB5b3VyIHBsb3QKIyByZXByb2R1Y3Rpb24gb2YgdGhlIGFib3ZlIHBsb3Qgd2l0aCBjbGFzcyBhZGRlZCBhcyBhIGNvbG9yCmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBjbGFzcykpCmBgYApgYGB7cn0KI2NsYXNzIGlzIGFuIHVub3JkZXJlZCB2YXIsIHNvIGl0IG1heSBub3QgYmUgb3B0aW1hbCB0byBtYXAgaXQgdXNpbmcgc2l6ZQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNpemUgPSBjbGFzcykpCmBgYAoKYGBge3J9CiMgYWxwaGEgaXMgdHJhbnNwYXJlbmN5CmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGFscGhhID0gY2xhc3MpKQoKIyBzaGFwZSBoYXMgc2l4IHNoYXBlcyB1c2VkCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNoYXBlID0gY2xhc3MpKQpgYGAKciBydWxlcwpgYGB7cn0KIyB0aGUgYWVzdGhldGljIHByb3BlcnRpZXMgbWF5IGJlIG1hbnVhbGx5IHNldApnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgY29sb3IgPSAicGluayIpCmBgYApgYGB7cn0KIyB0aGUgYWVzdGhldGljIHByb3BlcnRpZXMgbWF5IGJlIG1hbnVhbGx5IHNldAojCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNpemUgPSBjdHkpKQoKZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBjdHkpKQpgYGAKVGhlc2UgcGxvdHMgc2V0IGEgY29udGludW91cyB2YXJpYWJsZSAoY2l0eSBtaWxlYWdlKSB0byBkaWZmZXJlbnQgYWVkdGhldGljIG1hcmtlcnMKYGBge3J9CiMgMy41IEZhY2V0cwojIGFub3RoZXIgbWV0aG9kIGZvciBtdWx0aSB2YXJpYWJsZSBkYXRhIHBsb3R0aW5nCiMgdmFyIHRvIGZhY2V0IHdyYXAgc2hvdWxkIGJlIGRpc2NyZXRlCgojZXhhbXBsZSBvZiAxIHZhcmlhYmxlIGZhY2V0aW5nCmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF93cmFwKH5jbGFzcywgbnJvdyA9IDIpCgpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZmFjZXRfZ3JpZCgufmNsYXNzKQpgYGAKQSBwbG90IG9mIGhpZ2h3YXkgbWlsZWFnZSBhZ2FpbnN0IGRpc3BsYXksIGZhY2V0ZWQgYnkgY2xhc3Mgb2YgdmVoaWNsZSwgb25lIHZhcmlhYmxlCmBgYHtyfQojIGV4YW1wbGUgb2YgMi12YXIgZmFjZXRpbmcKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoZHJ2fmNsYXNzKQoKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoZHJ2fmN5bCkKCmBgYApQbG90IG9mIGRhdGEgZmFjZXRlZCBvbiB0d28gdmFyaWFibGVzCmBgYHtyfQojIDMuNiBHZW9tZXRyaWMgT2JqZWN0cwojIGEgJ2dlb20nIGlzIHRoZSBnZW9tZXRyaWNhbCBvYmplY3QgdGhhdCBhIHBsb3QgdXNlcyB0byByZXByZXNlbnQgZGF0YQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkKCiMgdGhlc2Ugb24gdGhlIHNhbWUgcGxvdAojbm90ZTogcGFzcyB0aGUgbWFwcGluZ3MgdG8gdGhlIGdncGxvdCBmdW5jdGlvbiB0byBhdm9pZCBkdXBsaWNhdGlvbiBlcnJvcnMKCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgoKQpgYGAKZGlmZmVyZW50IGdlb21ldHJpYyByZXByZXNlbnRhdGlvbnMgb2YgdGhlIHNhbWUgZGF0YQpgYGB7cn0KI2RpZmZlcmVudCBhZXN0aGV0aWNzIGNhbiBiZSBkaXNwbGF5ZWQgaW4gZGlmZmVyZW50IGxheWVycwpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhjb2xvciA9IGNsYXNzKSkgKyAKICBnZW9tX3Ntb290aCgpCmBgYApzYW1lIHBsb3QgYXMgZmlnIDE0LmMgLCB3aXRoIHRoZSBzY2F0dGVyIHBsb3QgY29sb3JlZCBieSBjbGFzcwpgYGB7cn0KIyBsb2NhbCBkYXRhIGFyZ3VtZW50cyB3aWxsIG92ZXJyaWRlIGdsb2JhbHMgCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gY2xhc3MpKSArIAogIGdlb21fc21vb3RoKGRhdGEgPSBmaWx0ZXIobXBnLCBjbGFzcyA9PSAic3ViY29tcGFjdCIpLCBzZSA9IEZBTFNFKQpgYGAKU2FtZSBwbG90IGFzIGZpZyAxNSB3aXRoIGxpbmUgZmlsdGVyZWQgdG8gaW5jbHVkZSBvbmx5IGNsYXNzIHN1YmNvbXBhY3QKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBkcnYpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpCmBgYApgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKGdyb3VwID0gZHJ2KSkKCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gZHJ2KSkgKyAKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQoKZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBkcnYpKSArIAogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMobGluZXR5cGUgPSBkcnYpLCBzZSA9IEZBTFNFKQpgYGAKYGBge3J9CiMgU3RhdGlzdGljYWwgVHJhbnNmb3JtcwojYmFyIGNoYXJ0cywgaGlzdG9ncmFtcywgZnJlcXVlbmN5IHBvbHlnb25zIGJpbiBhbmQgY291bnQgZGF0YQojc21vb3RoZXJzIGZpdCBhIG1vZGVsIHRvIHlvdXIgZGF0YSwgcGxvdCBwcmVkaWN0aW9ucyBjb21lIGZyb20gdGhpcyBtb2RlbCAKIyBib3ggcGxvdHMgY29tcHV0ZSBhIHN1bW1hcnkgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YQoKI3N0YXRfcGxvdCBjYW4gYmUgdXNlZCBpbnN0ZWFkIG9mIGdlb21fYmFyIGhlcmUKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCkpCmBgYApjaGFydCBvZiBkaWFtb25kIGNvdW50IGJ5IGN1dCBxdWFsaXR5CmBgYHtyfQojIHVzZSBnZW9tX2JhciB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBzdGF0CmRlbW8gPC0gdHJpYmJsZSgKICB+Y3V0LCAgICAgICAgIH5mcmVxLAogICJGYWlyIiwgICAgICAgMTYxMCwKICAiR29vZCIsICAgICAgIDQ5MDYsCiAgIlZlcnkgR29vZCIsICAxMjA4MiwKICAiUHJlbWl1bSIsICAgIDEzNzkxLAogICJJZGVhbCIsICAgICAgMjE1NTEKKQoKZ2dwbG90KGRhdGEgPSBkZW1vKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gZnJlcSksIHN0YXQgPSAiaWRlbnRpdHkiKQoKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBzdGF0X3N1bW1hcnkoCiAgICBtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBkZXB0aCksCiAgICBmdW4ueW1pbiA9IG1pbiwKICAgIGZ1bi55bWF4ID0gbWF4LAogICAgZnVuLnkgPSBtZWRpYW4KICApCmBgYApmaWcgYSA6cGxvdHRlZCBhZ2FpbnN0IGZyZXF1ZW5jeSwgbm90IHNpbXBseSBjb3VudApmaWcgYjogc3RhdGlzdGljcyBzdW1tYXJ5IG9mIGN1dCBhZ2FpbnN0IGRlcHRoCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArIAogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGNsYXJpdHkpKQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBjdXQsIGZpbGwgPSBjbGFyaXR5KSkgKyAKICBnZW9tX2JhcihhbHBoYSA9IDEvNSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBjdXQsIGNvbG91ciA9IGNsYXJpdHkpKSArIAogIGdlb21fYmFyKGZpbGwgPSBOQSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKQoKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGZpbGwgPSBjbGFyaXR5KSwgcG9zaXRpb24gPSAiZmlsbCIpCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY2xhcml0eSksIHBvc2l0aW9uID0gImRvZGdlIikKYGBgCkNvbG9yZWQgR3JhcGhzLGludHJvZHVjZXMgYSBuZXcgdmFyLCBvcmdhbml6ZWQgYnkgcG9zaXRpb24gYWRqdXN0bWVudApgYGB7cn0KIyBqaXR0ZXIgdG8gdmlldyBhbGwgZGF0YSBwb2ludHMgd2l0aCBhIHNtYWxsIGFtb3VudCBvZiBub2lzZSwgYXMgdmlldyBhbGwgb2YgdGhlbQojc29tZSB3aWxsIGJlIG9ic2N1cmVkCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSwgcG9zaXRpb24gPSAiaml0dGVyIikKYGBgCkppdHRlcmVkIHZzLiBub24taml0dGVyZWQKYGBge3J9CiMgMy45IENvb3JkaW5hdGUgc3lzdGVtcwpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gY2xhc3MsIHkgPSBod3kpKSArIAogIGdlb21fYm94cGxvdCgpCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjbGFzcywgeSA9IGh3eSkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKZmxpcHBpbmcgY29vcmRpbmF0ZSBzeXN0ZW1zIGlzIHVzZWZ1bCBmb3IgZGlzcGxheWluZyBob3JpemFudGFsIGJveHBsb3RzIApgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygibWFwcyIpCmxpYnJhcnkobWFwcykKbno8LSBtYXBfZGF0YSgibnoiKQoKZ2dwbG90KG56LCBhZXMobG9uZyxsYXQsIGdyb3VwID0gZ3JvdXApKSArCiAgZ2VvbV9wb2x5Z29uKGZpbGwgPSAicGluayIsIGNvbG91ciA9ICJibGFjayIpCiNjb29yZF9xdWlja21hcCBzZXRzIHRoZSBjb3JyZWN0IHJhdGlvIGZvciBnZW9zcGF0aWFsIGRhdGEKZ2dwbG90KG56LCBhZXMobG9uZywgbGF0LCBncm91cCA9IGdyb3VwKSkgKwogIGdlb21fcG9seWdvbihmaWxsID0gInBpbmsiLCBjb2xvdXIgPSAiYmxhY2siKSArCiAgY29vcmRfcXVpY2ttYXAoKQpgYGAKYGBge3J9CmJhciA8LSBnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArIAogIGdlb21fYmFyKAogICAgbWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY3V0KSwgCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgd2lkdGggPSAxCiAgKSArIAogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkKCmJhciArIGNvb3JkX2ZsaXAoKQpiYXIgKyBjb29yZF9wb2xhcigpCmBgYApgYGB7cn0KIyBEYXRhIFRyYW5zZm9ybWF0aW9uCmxpYnJhcnkobnljZmxpZ2h0czEzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgpgYGB7cn0KZmxpZ2h0cwpgYGAKCmBgYHtyfQojIDUuMiBmaWx0ZXIKIyBzZWxlY3QgYWxsIGZsaWdodHMgb24gSmFuIDFzdApqYW4xIDwtZmlsdGVyKGZsaWdodHMsIG1vbnRoID09IDEsIGRheSA9PSAxKQpqYW4xCmBgYApgYGB7cn0Kbm92X2RlYyA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggJWluJSBjKDExLCAxMikpCm5vdl9kZWMyIDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxMSB8IG1vbnRoID09IDEyKQpgYGAKCmBgYHtyfQojIDUuMyBBcnJhbmdlCmFycmFuZ2UoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkKYGBgCmBgYHtyfQphcnJhbmdlKGZsaWdodHMsIGRlc2MoYXJyX2RlbGF5KSkKYGBgCgpgYGB7cn0KIyA1LjYgR3JvdXBlZCBTdW1tYXJpZXMKYnlfZGF5IDwtIGdyb3VwX2J5KGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpCnN1bW1hcmlzZShieV9kYXksIGRlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpCmBgYAoKYGBge3J9CiMgZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW0gdGhlIGRpc3RhbmNlIGFuZCB0aGUgYW5nLiBkZWxheSBmb3IgZWFjaCBsb2NhdGlvbgojZ3JvdXAgZmxpZ2h0cyBieSBkZXN0aW5hdGlvbgojc3VtbWFyaXplIHRvIGNvbXB1dGUgZGlzdGFuY2UsIGF2ZXJhZ2UgZGVsYXksICMgb2YgZmxpZ2h0cwojZmlsdGVyIG91dGxpZXJzIGFuZCBob25vbHVsdQojbmEucm0gPSBUUlVFIHJlbW92ZXMgbWlzc2luZyB2YWx1ZXMKYnlfZGVzdCA8LSBncm91cF9ieShmbGlnaHRzLCBkZXN0KQpkZWxheSA8LSBzdW1tYXJpc2UoYnlfZGVzdCwKICAgIGNvdW50ID0gbigpLAogICAgZGlzdCA9IG1lYW4oZGlzdGFuY2UsIG5hLnJtID0gVFJVRSksCiAgICBkZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpCikKCmRlbGF5IDwtIGZpbHRlcihkZWxheSxjb3VudCA+MjAsIGRlc3QgIT0gIkhOTCIpCgpnZ3Bsb3QoZGF0YSA9IGRlbGF5LCBtYXBwaW5nID0gYWVzKHggPSBkaXN0LCB5ID0gZGVsYXkpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGNvdW50KSwgYWxwaGEgPSAxLzMpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQoKCiN1c2luZyBwaXBlcyB0byBtYWtlIHZhcmlhYmxlIG5hbWluZyBhbmQgYW5hbHlzaXMgZWFzaWVyCmRlbGF5cyA8LSBmbGlnaHRzICU+JSAKICBncm91cF9ieShkZXN0KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgY291bnQgPSBuKCksCiAgICBkaXN0ID0gbWVhbihkaXN0YW5jZSwgbmEucm0gPSBUUlVFKSwKICAgIGRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkKICApICU+JSAKICBmaWx0ZXIoY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikKYGBgCmBgYHtyfQpiYXR0aW5nIDwtIGFzX3RpYmJsZShMYWhtYW46OkJhdHRpbmcpCgpiYXR0ZXJzIDwtIGJhdHRpbmcgJT4lIAogIGdyb3VwX2J5KHBsYXllcklEKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgYmEgPSBzdW0oSCwgbmEucm0gPSBUUlVFKSAvIHN1bShBQiwgbmEucm0gPSBUUlVFKSwKICAgIGFiID0gc3VtKEFCLCBuYS5ybSA9IFRSVUUpCiAgKQoKYmF0dGVycyAlPiUgCiAgZmlsdGVyKGFiID4gMTAwKSAlPiUgCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGFiLCB5ID0gYmEpKSArCiAgICBnZW9tX3BvaW50KCkgKyAKICAgIGdlb21fc21vb3RoKHNlID0gRkFMU0UpCiM+IGBnZW9tX3Ntb290aCgpYCB1c2luZyBtZXRob2QgPSAnZ2FtJwpgYGAKYGBge3J9CiMgNyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCiNHZW5lcmF0ZSBRdWVzdGlvbnMgYWJvdXQgeW91ciBkYXRhCiNzZWFyY2ggZm9yIGFuc3dlcnMgdXNpbmcgdmlzdWFsaXphdGlvbiBhbmQgdHJhbnNmb3JtYXRpb24sIGFuZCBtb2RlbGluZwojdXNlIHdoYXQgeW91IGxlYXJuIHRvIHJlZmluZSB5b3VyIHF1ZXN0aW9ucyBhbmQgZ2VuZXJhdGUgbmV3IHF1ZXN0aW9ucwoKIyA3LjMgVmFyaWF0aW9uCiMgdGVuZGVuY3kgb2YgdGhlIHZhbHVlcyBvZiBhIHZhcmlhYmxlIHRvIGNoYW5nZSBmcm9tIG1lYXN1cmVlbnQgdG8gbWVhc3VyZW1lbnQKIyB2aXN1YWxpemluZyBkaXN0cmlidXRpb25zOiBjYXRlZ3BvcmljYWwgb3IgY29udGludW91cyAKIyBjYXRlZ29yaWNhbCAtLSB1c2UgYSBiYXIgY2hhcnQKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCkpCmRpYW1vbmRzICU+JQogIGNvdW50KGN1dCkKYGBgCnRoZSBoaWVnaHQgb2YgdGhlIGJhcnMgc2hvd3MgaG93IG1hbnkgb2JzZXJ2YXRpb25zIG9mIHRoZSBkYXRhIG9jY3VyZWQgYXQgZWFjaCB4IHZhbHVlCmBgYHtyfQojIHVzZSBhIGhpc3RncmFtIGZvciBjb250aW51b3VzIGRhdGEKIyBiaW53aWR0aCBvcmdhbml6ZXMgZWFjaCB2YWx1ZSB3aXRoIHNldCBib3VuZGFyaWVzCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSBjYXJhdCksIGJpbndpZHRoID0gMC41KQoKZGlhbW9uZHMgJT4lIAogIGNvdW50KGN1dF93aWR0aChjYXJhdCwgMC41KSkKI0RpZmZlcmVudCBiaW53aWR0aHMgY291bGQgcmV2ZWFsIGRpZmZlcmVudCByZWFsdGlvbnNoaXBzIGluIHRoZSBkYXRhCnNtYWxsZXIgPC0gZGlhbW9uZHMgJT4lIAogIGZpbHRlcihjYXJhdCA8IDMpCiAgCmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjEpCmBgYAoKYGBge3J9CmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIGNvbG91ciA9IGN1dCkpICsKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMC4xKQpgYGAKYGBge3J9CmdncGxvdChkYXRhID0gZmFpdGhmdWwsIG1hcHBpbmcgPSBhZXMoeCA9IGVydXB0aW9ucykpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjEpCmBgYAoKYGBge3J9CiMgNy41IENvdmFyaWF0aW9uCiMgdGVuY2RlbmN5IGZvciB0d28gdmFsdWVzIHRvIGJlIHJlbGF0ZWQKIyBob3cgZG9lcyB0aGUgcHJpY2Ugb2YgYSBkaWFtb25kIHZhcnkgd2l0aCBpdHMgcXVhbGl0eT8KCmdncGxvdChkYXRhID0gZGlhbW9uZHMsIG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IHByaWNlKSkgKwogIGdlb21fYm94cGxvdCgpCgpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBwcmljZSwgeSA9IC4uZGVuc2l0eS4uKSkgKyAKICBnZW9tX2ZyZXFwb2x5KG1hcHBpbmcgPSBhZXMoY29sb3VyID0gY3V0KSwgYmlud2lkdGggPSA1MDApCgpnZ3Bsb3QoZGlhbW9uZHMpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0KSkKYGBgCmBgYHtyfQojIGhvdyBkb2VzIGhpZ2h3YXkgbWlsZWFnZSB2YXJ5IGFjcm9zcyBjbGFzc2VzIG9mIHZlaGljbGVzPwpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKGNsYXNzLCBod3ksIEZVTiA9IG1lZGlhbiksIHkgPSBod3kpKQpgYGAKCmBgYHtyfQojIFR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fY291bnQobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gY29sb3IpKQpgYGAKCmBgYHtyfQpkaWFtb25kcyAlPiUgCiAgY291bnQoY29sb3IsIGN1dCkgJT4lICAKICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gY29sb3IsIHkgPSBjdXQpKSArCiAgICBnZW9tX3RpbGUobWFwcGluZyA9IGFlcyhmaWxsID0gbikpCmBgYApgYGB7cn0KIyB0d28gY29udGludW91cyB2YXJpYWJsZXMKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCmBgYAoKYGBge3J9CiNiaW5uaW5nIGZvciB0d28gY29udGludW91cyB2YXJpYWJsZXMgaXMgaGVscGZ1bCB0byB2aXN1YWxpemUgbGFyZ2UgZGF0YQoKZ2dwbG90KGRhdGEgPSBzbWFsbGVyKSArCiAgZ2VvbV9iaW4yZChtYXBwaW5nID0gYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkKCmluc3RhbGwucGFja2FnZXMoImhleGJpbiIpCmdncGxvdChkYXRhID0gc21hbGxlcikgKwogIGdlb21faGV4KG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKQpgYGAKCmBgYHtyfQojYW5vdGhlciBvcHRpb24gaXMgdG8gYmluIG9uZSBjb250aW51b3VzIHZhcmlhYmxlIHNvIGl0IGJlaGF2ZXMgbGlrZSBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlCmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsgCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoZ3JvdXAgPSBjdXRfd2lkdGgoY2FyYXQsIDAuMSkpKQpgYGAKCmBgYHtyfQoKIyA3IFBhdHRlcm5zIGFuZCBtb2RlbHMKIyBidWlsZCBhIG1vZGVsIHRoYXQgcHJlZGljdHMgcHJpY2UgZnJvbSBjYXJhdAojY29tcHV0ZXMgcmVzaWR1YWxzCmxpYnJhcnkobW9kZWxyKQoKbW9kIDwtIGxtKGxvZyhwcmljZSkgfiBsb2coY2FyYXQpLCBkYXRhID0gZGlhbW9uZHMpCmRpYW1vbmRzMiA8LSBkaWFtb25kcyAlPiUgCiAgYWRkX3Jlc2lkdWFscyhtb2QpICU+JSAKICBtdXRhdGUocmVzaWQgPSBleHAocmVzaWQpKQoKZ2dwbG90KGRhdGEgPSBkaWFtb25kczIpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBjYXJhdCwgeSA9IHJlc2lkKSkKCmBgYApyZWxhdGl2ZSB0byBzaXplLCBiZXR0ZXIgcXVhbGl0eSBkaWFtb25kcyBhcmUgbW9yZSBleHBlbnNpdmUKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMyKSArIAogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSByZXNpZCkpCmBgYAoKYGBge3J9CgojIHNhbWUgY29kZQoKZ2dwbG90KGRhdGEgPSBmYWl0aGZ1bCwgbWFwcGluZyA9IGFlcyh4ID0gZXJ1cHRpb25zKSkgKyAKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMC4yNSkKZ2dwbG90KGZhaXRoZnVsLCBhZXMoZXJ1cHRpb25zKSkgKyAKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMC4yNSkKYGBgCmBgYHtyfQojRGF0YSBXcmFuZ2xpbmcKI2dldHRpbmcgeW91ciBkYXRhIGludG8gUiAKI2ltcG9ydCwgdGlkeSwgdHJhbnNmb3JtCiMgMTAgVGliYmxlcwojIHRpYmJsZXMgYXJlIGRhdGEgZnJhbWVzIApsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgpgYGB7cn0KI2NvZXJjZSBhIHJlZ3VhbHIgZGF0YSBmcmFtZSB0byBhIHRpYmJsZQphc190aWJibGUoaXJpcykKCmBgYAoKYGBge3J9CiNjcmVhdGUgYSA1WDMgdGliYmxlCnRpYmJsZSgKICB4ID0gMTo1LCAKICB5ID0gMSwgCiAgeiA9IHggXiAyICsgeQopCmBgYAoKYGBge3J9CgoKdGliYmxlKAogIGEgPSBsdWJyaWRhdGU6Om5vdygpICsgcnVuaWYoMWUzKSAqIDg2NDAwLAogIGIgPSBsdWJyaWRhdGU6OnRvZGF5KCkgKyBydW5pZigxZTMpICogMzAsCiAgYyA9IDE6MWUzLAogIGQgPSBydW5pZigxZTMpLAogIGUgPSBzYW1wbGUobGV0dGVycywgMWUzLCByZXBsYWNlID0gVFJVRSkKKQpgYGAKCmBgYHtyfQojdGliYmxlcyB3aWxsIGF1dG9tYXRpY2FsbHkgcHJpbnQgdGhlIGZpcnN0IDEwIHJvd3Mgb2YgYSB0aWJibGUKI3RoaXMgY2FuIGJlIGN1c3RvbWl6ZWQKbnljZmxpZ2h0czEzOjpmbGlnaHRzICU+JSAKICBwcmludChuID0gMTAsIHdpZHRoID0gSW5mKQpgYGAKYGBge3J9CmRmIDwtIHRpYmJsZSgKICB4ID0gcnVuaWYoNSksCiAgeSA9IHJub3JtKDUpCikKIyBTdWJzZXR0aW5nCiMgW1sgXV0gZXh0cmFjdHMgYnkgbmFtZSBvciBwb3NpdGlvbgpkZltbMV1dCmRmW1sieCJdXQojICQgZXh0cmFjdHMgYnkgbmFtZSB3aWggbGVzcyB0eXBpbmcKZGYkeAoKI3VzZSBpbiBhIHBpcGUKZGYgJT4lIC4keApkZiAlPiUgLltbIngiXV0KCmBgYAoKYGBge3J9CiMgMjMgIE1vZGVsIEJhc2ljcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtb2RlbHIpCm9wdGlvbnMobmEuYWN0aW9uID0gbmEud2FybikKIyBEZWZpbmUgYSBmYW1pbHkgb2YgbW9kZWxzIHRoYXQgZXhwcmVzcyBhIHByZWNpc2UsIGJ1dCBnZW5lcmljIHBhdHRlcm4gKGkuZS4gYSBsaW5lLCBxdWFkcmF0aWMsIGV0YykKIyBnZW5lcmF0ZSBhIGZpdHRlZCBtb2RlbCBieSBtYWtpbmcgdGhlIGdlbmVyaWMgbW9kZWwgbW9yZSBzcGVjaWZpYwoKZ2dwbG90KHNpbTEsIGFlcyh4LCB5KSkgKyAKICBnZW9tX3BvaW50KCkKYGBgClNpbXVsYXRlZCBQbG90IHdpdGggYSBzdHJvbmcgcGF0dGVybgpgYGB7cn0KI3JhbmRvbWx5IGdlbmVyYXRlIGEgZmV3IG1vZGVscyBhbmQgb3ZlcmxheSB0aGVtIG9uIHRoZSBkYXRhCm1vZGVscyA8LSB0aWJibGUoCiAgYTEgPSBydW5pZigyNTAsIC0yMCwgNDApLAogIGEyID0gcnVuaWYoMjUwLCAtNSwgNSkKKQpnZ3Bsb3Qoc2ltMSwgYWVzKHgsIHkpKSArIAogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQgPSBhMSwgc2xvcGUgPSBhMiksIGRhdGEgPSBtb2RlbHMsIGFscGhhID0gMS80KSArCiAgZ2VvbV9wb2ludCgpCmBgYApPdXIgZGF0YSB3aXRoIGEgYnVuY2ggb2Ygc2hpdHR5IG1vZGVscwpgYGB7cn0KIyBxdWFudGlmeSB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgZGF0YSBhbmQgYSBtb2RlbAojIGdlbmVyYXRlIG1vZGVsIHdpdGggdGhlIHNtYWxsZXN0IGRpc3RhbmNlIGZyb20gdGhlIGRhdGEgCiMgU3RlcCAxOiB0dXJuIG1vZGVsIGZhbWlseSBpbnRvIGFuIFIgZnVuY3Rpb24KbW9kZWwxIDwtIGZ1bmN0aW9uKGEsIGRhdGEpIHsKICBhWzFdICsgZGF0YSR4ICogYVsyXQp9Cm1vZGVsMShjKDcsIDEuNSksIHNpbTEpCm1lYXN1cmVfZGlzdGFuY2UgPC0gZnVuY3Rpb24obW9kLCBkYXRhKSB7CiAgZGlmZiA8LSBkYXRhJHkgLSBtb2RlbDEobW9kLCBkYXRhKQogIHNxcnQobWVhbihkaWZmIF4gMikpCn0KCgoKYGBgCgpgYGB7cn0KIyByb290LW1lYW4tc3F1YXJlZCBkZXZpYXRpb24KbWVhc3VyZV9kaXN0YW5jZShjKDcsIDEuNSksIHNpbTEpCmBgYApgYGB7cn0KI3VzZSBwdXJyciBmdW5jdGlvbiB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSBmb3IgYWxsIGJvdmUgZGVmaW5lZCBtb2RlbHMKc2ltMV9kaXN0IDwtIGZ1bmN0aW9uKGExLCBhMikgewogIG1lYXN1cmVfZGlzdGFuY2UoYyhhMSwgYTIpLCBzaW0xKQp9Cgptb2RlbHMgPC0gbW9kZWxzICU+JSAKICBtdXRhdGUoZGlzdCA9IHB1cnJyOjptYXAyX2RibChhMSwgYTIsIHNpbTFfZGlzdCkpCm1vZGVscwpgYGAKYGBge3J9CiMgb3ZlcmxheSB0aGUgMTAgYmVzdCBtb2RlbHMgb250byB0aGUgdGhlIGRhdGEKZ2dwbG90KHNpbTEsIGFlcyh4LCB5KSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAyLCBjb2xvdXIgPSAiZ3JleTMwIikgKyAKICBnZW9tX2FibGluZSgKICAgIGFlcyhpbnRlcmNlcHQgPSBhMSwgc2xvcGUgPSBhMiwgY29sb3VyID0gLWRpc3QpLCAKICAgIGRhdGEgPSBmaWx0ZXIobW9kZWxzLCByYW5rKGRpc3QpIDw9IDEwKQogICkKCmdncGxvdChzaW0xLCBhZXMoeCwgeSkpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMiwgY29sb3VyID0gImdyZXkzMCIpICsgCiAgZ2VvbV9hYmxpbmUoCiAgICBhZXMoaW50ZXJjZXB0ID0gYTEsIHNsb3BlID0gYTIsIGNvbG91ciA9IC1kaXN0KSwgCiAgICBkYXRhID0gZmlsdGVyKG1vZGVscywgcmFuayhkaXN0KSA8PSAxKQogICkKYGBgCmBgYHtyfQpnZ3Bsb3QobW9kZWxzLCBhZXMoYTEsIGEyKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpbHRlcihtb2RlbHMsIHJhbmsoZGlzdCkgPD0gMTApLCBzaXplID0gNCwgY29sb3VyID0gInJlZCIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSAtZGlzdCkpCmBgYAoKYGBge3J9CiNncmlkIHNlYXJjaCBmb3IgYmVzdCBtb2RlbApncmlkIDwtIGV4cGFuZC5ncmlkKAogIGExID0gc2VxKC01LCAyMCwgbGVuZ3RoID0gMjUpLAogIGEyID0gc2VxKDEsIDMsIGxlbmd0aCA9IDI1KQogICkgJT4lIAogIG11dGF0ZShkaXN0ID0gcHVycnI6Om1hcDJfZGJsKGExLCBhMiwgc2ltMV9kaXN0KSkKCmdyaWQgJT4lIAogIGdncGxvdChhZXMoYTEsIGEyKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpbHRlcihncmlkLCByYW5rKGRpc3QpIDw9IDEwKSwgc2l6ZSA9IDQsIGNvbG91ciA9ICJyZWQiKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gLWRpc3QpKSAKYGBgCmBgYHtyfQpnZ3Bsb3Qoc2ltMSwgYWVzKHgsIHkpKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGNvbG91ciA9ICJncmV5MzAiKSArIAogIGdlb21fYWJsaW5lKAogICAgYWVzKGludGVyY2VwdCA9IGExLCBzbG9wZSA9IGEyLCBjb2xvdXIgPSAtZGlzdCksIAogICAgZGF0YSA9IGZpbHRlcihncmlkLCByYW5rKGRpc3QpIDw9IDEwKQogICkKYGBgCmBgYHtyfQoKYGBgCgo=